#pragma once
#include <iostream>
#include <functional>

namespace cyq
{
    template <class T>
    class auto_ptr
    {
    public:
        auto_ptr(T *ptr = nullptr)
            : _ptr(ptr)
        {
            std::cout << "auto_ptr(T* ptr=nullptr)" << std::endl;
        }
        auto_ptr(auto_ptr<T> &ap)
            : _ptr(ap._ptr)
        {
            // 置空
            ap._ptr = nullptr;
            std::cout << " auto_ptr(auto_ptr<T>& ap)" << std::endl;
        }
        ~auto_ptr()
        {
            std::cout << "~auto_ptr()" << std::endl;
            delete _ptr;
        }

        T &operator*()
        {
            return *_ptr;
        }
        T *operator->()
        {
            return _ptr;
        }

    private:
        T *_ptr;
    };

    template <class T>
    class unique_ptr
    {
    public:
        unique_ptr(T *ptr = nullptr)
            : _ptr(ptr)
        {
            std::cout << "unique_ptr(T* ptr)" << std::endl;
        }

        // 禁止拷贝
        unique_ptr(unique_ptr<T> &up) = delete;
        unique_ptr<T> &operator=(unique_ptr<T> &upd) = delete;

        ~unique_ptr()
        {
            std::cout << "~unique_ptr()" << std::endl;
            delete _ptr;
        }

        T &operator*()
        {
            return *_ptr;
        }
        T *operator->()
        {
            return _ptr;
        }

    private:
        T *_ptr;
    };

    template <class T>
    class shared_ptr
    {
    public:
        shared_ptr(T *ptr = nullptr)
            : _ptr(ptr), _count(new int(1))
        {
            std::cout << "shared_ptr(T* ptr)" << std::endl;
        }

        // 定制删除器
        template <class D>
        shared_ptr(T *ptr, D del)
            : _ptr(ptr), _count(new int(1)), _del(del)
        {
            std::cout << "shared_ptr(T* ptr,D del)" << std::endl;
        }

        // 拷贝构造
        shared_ptr(shared_ptr<T> &sp)
            : _ptr(sp._ptr), _count(sp._count)
        {
            (*_count)++;
        }

        // 赋值运算符重载
        shared_ptr<T> &operator=(shared_ptr<T> &sp)
        {
            // 自己给自己赋值
            if (sp._ptr == _ptr)
            {
                return *this;
            }

            if ((--(*_count)) == 0)
            {
                _del(_ptr);
                delete _count;
            }

            _count = sp._count;
            _ptr = sp._ptr;
            (*_count)++;

            return *this;
        }
        ~shared_ptr()
        {
            if ((--(*_count)) == 0)
            {
                std::cout << "~shared_ptr()" << std::endl;
                _del(_ptr);
                delete _count;
            }
        }
        T &operator*()
        {
            return *_ptr;
        }
        T *operator->()
        {
            return _ptr;
        }

        int use_count() const
        {
            return *_count;
        }

        T *get() const
        {
            return _ptr;
        }

    private:
        T *_ptr;
        int *_count;
        std::function<void(T *)> _del = [](T *ptr)
        { delete ptr; }; // 回调函数
    };

    template <class T>
    class weak_ptr
    {
    public:
        weak_ptr()
            : _ptr(nullptr)
        {
        }
        weak_ptr(weak_ptr<T> &sp)
            : _ptr(sp._ptr)
        {
        }
        weak_ptr(shared_ptr<T> &sp)
            : _ptr(sp.get())
        {
        }
        weak_ptr<T> operator=(const shared_ptr<T> &sp)
        {
            _ptr = sp.get();
            return *this;
        }

        weak_ptr<T> operator=(const weak_ptr<T> &sp)
        {
            _ptr = sp._ptr;
            return *this;
        }
        T &operator*()
        {
            return *_ptr;
        }
        T *operator->()
        {
            return _ptr;
        }

    private:
        T *_ptr;
    };

}
